package cm.tl.pms.util;

import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.ReadTimeoutHandler;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;

import java.util.Map;

public class WebClientUtil {
    private final String baseUrl;
    private final WebClient client;

    /**
     * 构造函数
     *
     * @param baseUrl IP 接口的基础 URL
     */
    public WebClientUtil(String baseUrl) {
        this.baseUrl = baseUrl;
        this.client = createWebClient();
    }

    /**
     * 创建 WebClient 对象，关联 HttpClient
     *
     * @return WebClient 对象
     */
    private WebClient createWebClient() {
        // 创建 HttpClient 对象，设置连接池、超时等参数
        HttpClient httpClient = HttpClient.create()
                .tcpConfiguration(tcpClient ->
                        tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 50000)
                                .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(50)))
                                .option(ChannelOption.SO_KEEPALIVE, true)
                                .option(ChannelOption.TCP_NODELAY, true));

        // 创建 ReactorClientHttpConnector 对象，将 WebClient 和 HttpClient 进行关联
        ReactorClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);

        // 创建请求客户端 WebClient 对象
        return WebClient.builder()
                .baseUrl(baseUrl)
                .clientConnector(connector)
                .filter(logRequest())
                .filter(logResponse())
                .build();
    }

    /**
     * 发送 GET 请求
     *
     * @param uri 请求的 URI
     * @return 响应结果
     */
    public Mono<String> get(String uri) {
        return client.get()
                .uri(uri)
                .retrieve()
                .onStatus(HttpStatus::isError, response ->
                        response.bodyToMono(String.class).flatMap(errorMsg -> {
                            System.out.println("请求出错：" + errorMsg);
                            return Mono.error(new Exception(errorMsg));
                        }))
                .bodyToMono(String.class);
    }

    /**
     * 发送同步 GET 请求
     *
     * @param uri 请求的 URI
     * @return 响应结果
     */
    public String getSync(String uri) {
        return client.get()
                .uri(uri)
                .retrieve()
                .onStatus(HttpStatus::isError, response ->
                        response.bodyToMono(String.class).flatMap(errorMsg -> {
                            System.out.println("请求出错：" + errorMsg);
                            return Mono.error(new Exception(errorMsg));
                        }))
                .bodyToMono(String.class)
                .block();  // block for the response
    }

    /**
     * 发送 POST 请求
     *
     * @param uri  请求的 URI
     * @param body 请求体
     * @return 响应结果
     */
    public Mono<String> post(String uri, String body) {
        return client.post()
                .uri(uri)
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(body))
                .exchange()
                .flatMap(response -> {
                    if (response.statusCode().equals(HttpStatus.OK)) {
                        return response.bodyToMono(String.class);
                    } else {
                        return response.bodyToMono(String.class)
                                .flatMap(errorMsg -> Mono.error(new Exception(errorMsg)));
                    }
                });
    }

    /**
     * 发送同步 POST 请求
     *
     * @param uri  请求的 URI
     * @param body 请求体
     * @return 响应结果
     */
    public String postSync(String uri, String body) {
        return client.post()
                .uri(uri)
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(body))
                .retrieve()
                .onStatus(HttpStatus::isError, response ->
                        response.bodyToMono(String.class).flatMap(errorMsg -> {
                            System.out.println("请求出错：" + errorMsg);
                            return Mono.error(new Exception(errorMsg));
                        }))
                .bodyToMono(String.class)
                .block();  // block for the response
    }

    public Map<String, Object> postToMap(String path, MultiValueMap<String, String> params) {
        try {
            return client.post()
                    .uri(path)
                    .bodyValue(params)
                    .retrieve()
                    .bodyToMono(Map.class)
                    .block();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 日志过滤器，用于打印请求信息
     *
     * @return ExchangeFilterFunction 对象
     */
    private ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            System.out.println("发送请求：" + clientRequest.method() + " " + clientRequest.url());
            clientRequest.headers().forEach((name, values) -> values.forEach(value -> System.out.println(name + ": " + value)));
            return Mono.just(clientRequest);
        });
    }

    /**
     * 日志过滤器，用于打印响应信息和错误信息
     *
     * @return ExchangeFilterFunction 对象
     */
    private ExchangeFilterFunction logResponse() {
        return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
            System.out.println("收到响应：" + clientResponse.statusCode() + " " + clientResponse.headers().asHttpHeaders());
            if (clientResponse.statusCode().isError()) {
                return clientResponse.bodyToMono(String.class)
                        .flatMap(errorMsg -> {
                            System.out.println("请求出错：" + errorMsg);
                            return Mono.error(new Exception(errorMsg));
                        });
            } else {
                return Mono.just(clientResponse);
            }
        });
    }


    public static void main(String[] args) {
        WebClientUtil util = new WebClientUtil("http://localhost:8072/modelProject/aiCmdIntent");

//        // 发送 GET 请求
//        util.get("/treasure/")
//                .subscribe(
//                        response -> {
//                            // 解析并处理响应结果
//                            System.out.println("GET 请求的响应结果：" + response);
//                            // TODO: 进行进一步的处理
//                        },
//                        error -> {
//                            // 处理请求出错的情况
//                            error.printStackTrace();
//                            if (error instanceof WebClientResponseException.NotFound) {
//                                // 如果返回了 404 错误，输出错误信息
//                                String errorMsg = ((WebClientResponseException.NotFound) error).getResponseBodyAsString();
//                                System.out.println("GET 请求出错：" + errorMsg);
//                            } else {
//                                System.out.println("GET 请求出错：" + error.getMessage());
//                            }
//                        }
//                );

        // 发送 POST 请求
        util.post("/proofreading", "{\"appId\":\"100\",\"tranceId\":\"65a8c5e5ed57d32fd8a33905\",\"content\":\"今天的天气不戳!\"}")
                .subscribe(
                        response -> {
                            // 解析并处理响应结果
                            System.out.println("POST 请求的响应结果：" + response);
                            // TODO: 进行进一步的处理
                        },
                        error -> {
                            // 处理请求出错的情况
                            System.out.println("POST 请求出错：" + error.getMessage());
                        }
                );

//        // 同步 GET 请求示例
//        String getResponse = util.getSync("/api/endpoint");
//        System.out.println("GET Response: " + getResponse);
//
//        // 同步 POST 请求示例
//        String postResponse = util.postSync("/api/endpoint", "{\"key\": \"value\"}");
//        System.out.println("POST Response: " + postResponse);
    }
}
